# Position 定位

# 为什么需要定位

以下情况使用标准流或者浮动能实现吗?

  • 某个元素可以自由的在一个盒子内移动位置,并且压住其他盒子
  • 当我们滚动窗口的时候,盒子是固定屏幕某个位置的。

以上效果,标准流或浮动都无法快速实现,此时需要定位来实现。

  • 浮动可以让多个块级盒子一行没有缝隙排列显示, 经常用于横向排列盒子。
  • 定位则是可以让盒子自由的在某个盒子内移动位置或者固定屏幕中某个位置,并且可以压住其他盒子。
  • 内联 inline 元素不能使用定位,需转换为 block 元素🔥

# 定位组成

  • 定位:将盒子定在某一个位置,所以定位也是在摆放盒子,按照定位的方式移动盒子。
  • 定位 = 定位模式 + 边偏移
  • 定位模式决定元素的定位方式 ,它通过 CSS 的 position 属性来设置

# static 静态定位

默认值,静态定位,元素出现在标准流中(忽略 top, bottom, left, right 或者 z-index 声明,即没有边偏移)很少用到。

# relative 相对定位 🔥

# 简介

  • 相对定位相对于元素在文档流中的原来位置进行定位

  • 元素开启相对定位以后,如果不设置偏移量元素不会发生任何的变化

  • 会提升元素的层级。可能会覆盖在其他元素之上,所以不影响其他元素布局即新的位置不会占用其他元素空间

  • 没有脱标原来在标准流的位置继续占有,后面的盒子仍以标准流的方式对待它,不能使用该位置。灵魂出窍😂

    相对定位不会改变元素的性质,块还是块,行内还是行内

# 应用

最典型的应用是给绝对定位当爹的(限制绝对定位),以及对元素位置进行微调

# 首页大图居中案例

  • 显示大图主内容(居中)
  • 不能出现 x 轴滚动条
  • 所以 img 需要向左移动:(img-box)/2,化简为-img/2 + box/2
.box {
  /* 设置最小宽度 */
  min-width: 1000px;
  /* 隐藏多余的 */
  overflow: hidden;
}
.box img {
  /* 向左移动img一半 */
  position: relative;

  /* 硬编码不好,但是不能写%,因为此处%是相对于包含块即父元素,而我们需要的是相对于元素本身。可以选择translate百分比 */
  /* left: -960px; */
  transform: translate(-50%);

  /* 向右移动父元素的一半,使用百分数可以根据视窗灵活调整 */
  margin-left: 50%;
}

# absolute 绝对定位 🔥

# 简介

  • 绝对定位,相对于非 static 定位的最近祖先元素进行定位。最终还没找到,则相对于浏览器视口即 viewport 来定位

  • 开启绝对定位后,如果不设置偏移量元素的位置不会发生变化。偏移量(非z-index)赋值为0后位置可能会改变

  • 绝对定位会使元素提升一个层级

  • 脱标不再占有原先的位置,其他盒子可以使用原先位置

    改变元素的性质(脱标特点),行内变成块,块的宽高被内容撑开

# 子绝父相的由来

  • 在绝大多数情况下,子元素的绝对定位都是相对于父元素,好参考

  • 如果希望子元素相对父元素进行定位,又不希望父元素脱标!常用解决方案就是子绝父相

    • 子级绝对定位,不会占有位置,可以放到父盒子里面的任何一个地方,不会影响其他的兄弟盒子。
    • 父盒子需要加定位限制子盒子在父盒子内显示
    • 父盒子布局时,需要占有位置,因此父亲只能是相对定位(其他 float 等也不行)。
  • 当然,子绝父相不是永远不变的,如果父元素不需要占有位置,子绝父绝也会遇到。

# fixed 固定定位 🔥

  • 固定定位相对于浏览器视口即 viewport 进行定位,跟父元素没有任何关系。可以看做是一种特殊的绝对定位。即使画布滚动元素位置也不会改变。

  • 脱标不再占有原先的位置。其他盒子可以使用原先位置

    改变元素的性质(脱标特点),行内变成块,块的宽高被内容撑开

右侧固定按键案例(这个其实是配合 JS 实现的粘性定位):

  • 先不使用固定定位
  • 当画布移动到某个位置时,添加固定定位。配合 JS 实现

# Horizontal / Vertical Formatting

参考 W3C 文档和 MDN 文档

# Horizontal

对于绝对定位元素即 position 为 absolute 或 fixed 的元素来说。需要满足如下约束:

left + margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right + right
= 
width of containing block
  • 🔥上述值中只有 'width', 'margin-left' 和 'margin-right','left' 和 'right' 可以设置为 'auto',且 'width','left' 和 'right' 默认就是 'auto'。其余几个属性必须设置为特定的值或默认值为 0。width 只可设置为非负值,只有 'margin','left' 和 'right'可以为负值。
  • 🔥大多数情况下,height和width 被设定为auto的绝对定位元素,按其内容大小调整尺寸。但是,被绝对定位的元素可以通过指定top和bottom ,保留height未指定(即auto),来填充可用的垂直空间。它们同样可以通过指定left 和 right并将width 指定为auto来填充可用的水平空间。
  • 其他的文档中看不懂😓

水平方向同理!

# 案例

  • 若希望绝对定位元素的宽高和定位参考对象一样,可以给绝对定位元素设置如下属性

    <style>
      .box1 {
        position: relative;
        width: 500px;
        height: 500px;
        background-color: skyblue;
      }
    
      .box2 {
        position: absolute;
        background-color: orange;
        
        /* 绝对定位元素的宽高和定位参考对象一样 */
        /* left: 0;
        right: 0;
        top: 0;
        bottom: 0; */
    
        /* 绝对定位元素的宽和定位参考对象一样 */
        /* left: 0;
        right: 0;
        height: 100px; */
    
        /* 绝对定位元素的高和定位参考对象一样 */
        /* top: 0;
        bottom: 0;
        width: 100px; */
      }
    </style>
    <div class="box1">
      <div class="box2"></div>
    </div>
    
  • 若希望绝对定位元素在定位参考对象中居中(垂直 / 水平)显示(宽高确定!),可以给绝对定位元素设置如下属性

    <style>
    .box1 {
      position: relative;
      width: 500px;
      height: 500px;
      background-color: skyblue;
    }
    
    .box2 {
      position: absolute;
      background-color: orange;
      width: 100px;
      height: 100px;
    
      /* 水平且垂直居中 */
      /* left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      margin: auto; */
    
      /* 水平居中,margin 二选一*/
      /* left: 0;
      right: 0;
      margin: 0 auto;
      margin: auto */
    
      /* 垂直居中,margin 二选一 */
      /* top: 0;
      bottom: 0;
      margin: auto 0;
      margin: auto; */
    }
    </style>
    <div class="box1">
    	<div class="box2"></div>
    </div>
    
  • 当然也可以使用transform实现,特别适用于宽高不确定

    <style>
      .box1 {
        background-color: skyblue;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(50%, 50%);
      }
    </style>
    <div class="box1">666</div>
    

# sticky 粘性定位 🔥

  • 粘性定位可以被认为是相对定位 relative固定定位 fixed的混合

  • 以浏览器的可视窗口为参照点移动元素(固定定位特点)

  • 粘性定位占有原先的位置(相对定位特点)

  • 必须添加 top 、left、right、bottom 其中一个才有效

WARNING

跟页面滚动搭配使用。 兼容性较差,IE 不支持,目前大部分使用 JS 实现

# inherit 继承

规定应该从父元素继承 position 属性的值。

定位模式 是否脱标 移动位置 是否常用
static 静态定位 不能使用边偏移 很少
relative 相对定位 否 (占有原来位置) 相对于自身位置移动 常用
absolute 绝对定位 带有定位的父级 常用
fixed 固定定位 浏览器可视区 常用
sticky 粘性定位 否 (占有原来位置) 浏览器可视区 当前阶段少

# 偏移量 offset

边偏移就是定位的元素移动到最终位置,非定位元素使用无效

属性 描述
top 定义了一个定位元素的上外边距边界与其包含块上边界之间的偏移。
right 定义了定位元素右外边距边界与其包含块右边界之间的偏移。
bottom 定义了定位元素下外边距边界与其包含块下边界之间的偏移。
left 定义了定位元素左外边距边界与其包含块左边界之间的偏移。
overflow 设置当元素的内容溢出其区域时发生的事情。
clip 设置元素的形状。元素被剪入这个形状之中,然后显示出来。
vertical-align 设置元素的垂直对齐方式。
z-index 设置元素的堆叠顺序,z 轴距离,默认为 auto,可负数,数字后面不能加单位定位盒子才有该属性,如果属性值相同,则按照 HTML 元素的书写顺序,后来居上。

元素的层叠

  • 父子关系

    子元素会层叠在父元素上,无法通过z-index来控制

  • 非父子关系

    • 都是非定位元素(即 static):在标准流中一般不存在层叠现象
    • 1 个是定位、1 个是非定位:定位元素会层叠在非定位元素上
    • 都是定位元素:默认后写的 HTML 元素层叠在先写的上面,可以使用z-index来控制

TIP

若一个盒子既有 left 也有 right,则 left 优先级高;同理 top 比 bottom 优先级高

# 脱离标准流元素特点—重复 🔥

  • 可以设置widthheight
  • 默认widthheight由内容决定
  • 不再给父元素汇报widthheight数据,即父元素也不知道该元素了
  • 类似inline-block,但是不是!是block

注意

display、position、float 都都影响盒子的生成和布局:

  • 当 display 为 none 时,就不会生成盒子,对 position 和 float 无影响
  • 当 postion 为 absolute 或 fixed 时,或 float 为 left 或 right 时,元素基本都变为 block 类型(除了布局类型)详细参考文档

# 定位和浮动

  • 绝对定位(固定定位)会压住下面标准流所有的内容

    浮动元素不同,只会压住它下面标准流的盒子,但是不会压住下面标准流盒子里面的文字(图片)

    浮动之所以不会压住文字,因为浮动产生的目的最初是为了做文字环绕效果的。 文字会围绕浮动元素